Skip to content

feat(codex): author marketplace policy and record distribution/install policy parity (#188 S3) - #392

Merged
ScriptedAlchemy merged 7 commits into
mainfrom
feat/188-s3-codex-marketplace-policy
Sep 3, 2026
Merged

feat(codex): author marketplace policy and record distribution/install policy parity (#188 S3)#392
ScriptedAlchemy merged 7 commits into
mainfrom
feat/188-s3-codex-marketplace-policy

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Summary

Slice 3 of #188 (marketplace / install / policy). Stacked on #378 (merged).

  • codex.marketplace authors the emitted .agents/plugins/marketplace.json: picker displayName, entry category (defaults to the plugin's interface category instead of a hard-coded Productivity), and policy.installation / policy.authentication validated against the documented values (codex.marketplace.* diagnostics). The source stays the local ./ plugin root.
  • Pinned marketplace.schema.json now admits every documented source form — plain ./ string, { source: local }, Git root url (+ ref/sha), git-subdir, and npm (package, version without path/URL selectors, credential-free HTTPS registry) — with root containment and backslash rejection; tightenings recorded in PROVENANCE.
  • New distribution capability block (18 dated four-state rows) mirrored as adapter capabilities and intersected to honest unavailable on the unified target: repo/personal/legacy-Claude marketplace discovery, marketplace sources/interface/policy/category, install cache layout, config.toml enable state, codex plugin and codex plugin marketplace JSON contracts, features.plugins / features.hooks (+ deprecated codex_hooks), inline [hooks] TOML, managed requirements.toml, allow_managed_hooks_only, restrict_to_allowed_sources, workspace publishing (features.plugin_sharing). Submission/publish controls remain recorded as distribution policy (manifestPackage.submissionPolicy), not compiler behavior.
  • Honest tightening recorded from a live probe: the docs say local installs land under .../$PLUGIN/local/; codex-cli 0.147.0 uses the manifest version segment (installedPath = .../review-tools/1.2.3).
  • Codex adapter 1.7.0 → 1.8.0, unified plugin 1.22.0 → 1.23.0.

Evidence

  • Docs read 2026-09-02: https://developers.openai.com/plugins/build/plugins, https://learn.chatgpt.com/docs/developer-commands?surface=cli, https://learn.chatgpt.com/docs/enterprise/managed-configuration, https://learn.chatgpt.com/docs/hooks.
  • Native proof (AGENT_BUNDLE_NATIVE_HOST_CONTRACTS=1, isolated CODEX_HOME, codex-cli 0.147.0): new test pins the Codex plugin and marketplace CLI JSON contracts, cache layout, and enable state for an authored marketplace policymarketplace add/list/upgrade/remove --json, plugin add/list/remove --json fields match the documented contracts; authored INSTALLED_BY_DEFAULT/ON_USE echoed as installPolicy/authPolicy; config.toml [plugins."<id>"] enabled = true + [marketplaces.<name>] written and removed. 3/3 Codex native probes passed locally.
  • New tests/codex-distribution.test.ts (13 tests: rows, source-form matrix, defaults, authored fields, diagnostics).
  • Local gates after rebase onto main: pnpm typecheck ✅, pnpm lint ✅ (0 errors), pnpm test:route-unit ✅ 35, pnpm test:projection ✅ 63, pnpm build && pnpm test:integration:run ✅ 938/938 (pre-rebase run). pnpm test:unit: 2689 passed; 4 failures were load-induced timeouts on a machine at load average 150 (event-ipc live-server collision, mcp-probe-service teardown timeout, native-claude-contract 5 s timeouts, rsc-runtime/dispatcher 150 ms deadline) in modules this PR does not touch; native-claude-contract and lifecycle-replay pass when re-run with a longer timeout.

Test plan

  • pnpm exec rstest --config rstest.unit.config.ts packages/agent-bundle/tests/codex-distribution.test.ts packages/agent-bundle/tests/codex-hook-contract.test.ts packages/agent-bundle/tests/adapter-metadata.test.ts packages/agent-bundle/tests/adapter-capability-states.test.ts packages/agent-bundle/tests/host-adapters.test.ts
  • Native Codex probes (opt-in) against codex-cli 0.147.0
  • CI green

@changeset-bot

changeset-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e629711

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-bundle Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T08:01:38.740330Z e629711 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@pkg-pr-new

pkg-pr-new Bot commented Sep 3, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@392
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@392
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/runtime@392

commit: e629711

…l policy parity (#188 S3)

Author codex.marketplace displayName, category, and documented policy values
(category follows the plugin interface category), admit every documented
marketplace source form in the pinned schema, and publish dated four-state
distribution rows for marketplace discovery, sources, cache layout, enable
state, CLI JSON contracts, feature flags, managed requirements.toml,
allow_managed_hooks_only, restrict_to_allowed_sources, and workspace
publishing, backed by live codex-cli 0.147.0 probes.
@ScriptedAlchemy
ScriptedAlchemy force-pushed the feat/188-s3-codex-marketplace-policy branch from 5b56965 to d7e0550 Compare September 3, 2026 06:27
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d7e0550601

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

`Codex marketplace policy.installation must be one of ${marketplaceInstallationPolicies.join(', ')}.`,
));
} else {
policy.installation = installation;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Account for NOT_AVAILABLE in the installation flow

When an author selects the newly accepted NOT_AVAILABLE policy, the marketplace correctly marks this plugin as unavailable for installation, but both the generated instructions (src/install/surface.ts:44-45) and installPublicCli (src/install/install.ts:222-230) still unconditionally run codex plugin add. Thus a valid configuration produces a bundle whose advertised and programmatic installation path is rejected by the host; either reject this policy for self-installing bundles or make those installation surfaces policy-aware.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed with a live probe: codex-cli 0.147.0 accepts codex plugin marketplace add for a NOT_AVAILABLE entry and then refuses codex plugin add demo@demo-market with plugin demo is not available for install in marketplace demo-market — the exact command INSTALL.md and installBundle() run. Fixed in a809d0d: the adapter now rejects an authored installation: NOT_AVAILABLE with codex.marketplace.policy.installation.not-installable (schema still documents the enum value; the capability row records the probe and the rejection), so the self-installing artifact can no longer advertise an install path the host refuses. AVAILABLE and INSTALLED_BY_DEFAULT remain admitted, with tests for both sides.

},
"gitUrl": {
"minLength": 1,
"pattern": "^(?:[Hh][Tt][Tt][Pp][Ss]?://|[Ss][Ss][Hh]://|[A-Za-z0-9._-]+@[A-Za-z0-9.-]+:)\\S+$",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse marketplace URLs instead of matching only prefixes

When this schema validates an external marketplace, malformed values such as https://%zz/repository.git satisfy this new Git URL pattern, and the analogous registry pattern on line 52 accepts the same invalid authority. These are not usable URLs, so the advertised Git/npm source validation succeeds only for Codex or npm to fail during installation; validate the HTTP(S)/SSH variants structurally rather than relying solely on a scheme-prefix regex.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Fixed in a809d0d: gitUrl now requires http(s):// or ssh:// with optional userinfo, a syntactically valid hostname (label grammar, no bare %), optional port, and a non-empty percent-encoded repository path, or an scp-style user@host:path; the npm registry pattern uses the same hostname/port/path grammar (still credential-, query-, and fragment-free HTTPS). https://%zz/repository.git, https://, https://github.com:port/..., ssh://%zz/..., git@%zz:..., and https://%zz/ registries are now rejected, with the admitted/rejected matrix covered in codex-distribution.test.ts and the schema/PROVENANCE pins updated.

…and validate Git/registry URL structure

Live codex-cli 0.147.0 registers a NOT_AVAILABLE marketplace entry but refuses
`codex plugin add`, the exact command INSTALL.md and installBundle() run, so an
authored NOT_AVAILABLE now fails the build with
codex.marketplace.policy.installation.not-installable instead of emitting an
uninstallable bundle. The pinned marketplace schema's Git URL and npm registry
patterns now require a syntactically valid hostname, optional port, and a
percent-encoded path rather than a bare scheme prefix.

Addresses the two Codex review threads on #392.
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a809d0d274

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"$id": "https://agent-bundle.dev/schemas/codex/0.147.0/marketplace.schema.json",
"$defs": {
"containedPath": {
"pattern": "^\\./(?!(?:.*[\\/\\\\])?\\.\\.(?:[\\/\\\\]|$))[^\\\\]*$",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject traversal paths containing line breaks

When a local or git-subdir path contains a line break before a parent segment, such as ./safe\n/../outside, this pattern accepts it: the negative lookahead's .* does not cross line terminators, while the final [^\\]* does. Resolving that accepted path escapes the marketplace root, contradicting the containment guarantee; reject control characters or validate path segments without a dot-based lookahead.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed — . in the lookahead does not cross line terminators while the trailing [^\\]* did, so ./x\n/../../outside (and \r\n, U+2028, U+2029 variants) slipped past containment. Fixed in 7e818b9: containedPath (local and git-subdir) now rejects control characters and Unicode line terminators ([^\\\u0000-\u001F\u007F\u2028\u2029]), so the lookahead sees the whole string; the same flaw existed in the pinned plugin.schema.json component and interface-asset path patterns, so those are fixed alongside (PROVENANCE notes and byte/sha pins updated). Rejection cases added in codex-distribution.test.ts and host-adapters.test.ts.

},
"gitUrl": {
"minLength": 1,
"pattern": "^(?:(?:[Hh][Tt][Tt][Pp][Ss]?|[Ss][Ss][Hh])://(?:[A-Za-z0-9._~!$&'()*+,;=-]+@)?[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*(?::[0-9]{1,5})?(?:/(?:[A-Za-z0-9._~!$&'()*+,;=:@-]|%[0-9A-Fa-f]{2})+)+/?|[A-Za-z0-9._-]+@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*:(?:~?[A-Za-z0-9._!$&'()*+,;=@-]+)(?:/[A-Za-z0-9._~!$&'()*+,;=@-]+)*/?)$",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject URL ports above 65535

When a Git URL uses a five-digit out-of-range port, such as https://github.com:65536/org/repo.git, this pattern still validates it even though standard URL parsing rejects it; the npm registry pattern on line 53 has the same issue. Although the previously reported malformed-authority case is fixed, this is fresh evidence that the replacement regex still admits unusable URLs, so the port must be range-checked or the values parsed structurally.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7e818b9: the Git URL and npm registry port groups are now range-checked to 0–65535 (0*(?:0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]), leading zeros allowed as WHATWG parsing does). :65536 and :99999 are rejected for https://, ssh://, and registry URLs; :65535 and :0443 are admitted, with both sides in the test matrix.

…k URL ports in the pinned schemas

The containment lookahead used `.*`, which does not cross line terminators
while the trailing character class did, so `./x\n/../../outside` escaped the
marketplace or plugin root. Component, interface-asset, and marketplace path
patterns now reject control characters and Unicode line terminators. Git URL
and npm registry ports are range-checked to 0-65535.

Addresses the second-round Codex review threads on #392.
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7e818b9420

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

},
"gitUrl": {
"minLength": 1,
"pattern": "^(?:(?:[Hh][Tt][Tt][Pp][Ss]?|[Ss][Ss][Hh])://(?:[A-Za-z0-9._~!$&'()*+,;=-]+@)?[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*(?::0*(?:0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?(?:/(?:[A-Za-z0-9._~!$&'()*+,;=:@-]|%[0-9A-Fa-f]{2})+)+/?|[A-Za-z0-9._-]+@[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?(?:\\.[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*:(?:~?[A-Za-z0-9._!$&'()*+,;=@-]+)(?:/[A-Za-z0-9._~!$&'()*+,;=@-]+)*/?)$",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject invalid numeric IPv4 authorities

Fresh evidence after the earlier URL fix: this replacement pattern still accepts URLs such as https://999.999.999.999/team/plugin.git, even though standard WHATWG URL parsing rejects that authority as invalid; the registry pattern has the same gap. Consequently, an unusable Git or npm source passes artifact validation and is deferred to a host-side installation failure, so numeric IPv4-looking hosts should be parsed or range-checked rather than treated as arbitrary DNS labels.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 438b8ee. The host grammar in gitUrl, npmSource.registry, and the scp-style form is now: DNS labels whose last label contains a letter (so example.123 and 1.2.3 fail), or an in-range dotted-quad IPv4 ((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d) × 4, so 999.999.999.999, 256.1.1.1, and 1.2.3.4.5 fail). Rejected fixtures added in codex-distribution.test.ts for the HTTPS, ssh://, scp, and npm-registry forms; the admitted fixtures still cover 10.0.0.1 and 127.0.0.1:8443. PROVENANCE.json and the schema pin are updated.

"type": "string"
},
"source": { "const": "npm", "type": "string" },
"version": { "minLength": 1, "pattern": "^[^/\\\\:@]+$", "type": "string" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate npm version selectors rather than arbitrary text

When a marketplace entry supplies a malformed selector such as version: "foo bar" or version: "%", this pattern accepts it even though npm 11.4.2 rejects the resulting package specs with EINVALIDTAGNAME. Since this schema is intended to validate real-world npm marketplace sources before installation, restrict the field to valid versions, ranges, and dist-tags instead of merely excluding path/URL punctuation.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 438b8ee. npmSource.version is now a three-alternative pattern: a semver version (x.y.z[-pre][+build], optional v/= prefix), a semver range (comparator sets with x/X/* wildcards, ~/^/>=… operators, hyphen ranges, || unions), or a dist-tag composed only of characters encodeURIComponent leaves unescaped — the same rule npm-package-arg applies before raising EINVALIDTAGNAME. foo bar, %, "", 1.2.3 || foo bar, >=1.0.0 <, latest@1, a/b, a:b, a#b, and a?b are now rejected fixtures; latest, next, 1.2.3, ^1.2.0, >=1.0.0 <2.0.0, 1.x, 1.2.3-beta.1+build.5, and 1.0.0 - 2.0.0 remain admitted.

…sion selectors in the marketplace schema

Hosts must be DNS labels whose last label contains a letter or an in-range
dotted-quad IPv4, so https://999.999.999.999/repo.git no longer passes; npm
`version` must be a semver version, a semver range, or a dist-tag composed
only of characters encodeURIComponent leaves unescaped, matching the
npm-package-arg rules that otherwise fail with EINVALIDTAGNAME.

Addresses the third-round Codex review threads on #392.
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 438b8ee9fe

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

},
"gitUrl": {
"minLength": 1,
"pattern": "^(?:(?:[Hh][Tt][Tt][Pp][Ss]?|[Ss][Ss][Hh])://(?:[A-Za-z0-9._~!$&'()*+,;=-]+@)?(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)*(?=[A-Za-z0-9-]{1,63}(?:[:/]|$))(?=[0-9-]*[A-Za-z])[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)(?::0*(?:0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?(?:/(?:[A-Za-z0-9._~!$&'()*+,;=:@-]|%[0-9A-Fa-f]{2})+)+/?|[A-Za-z0-9._-]+@(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)*(?=[A-Za-z0-9-]{1,63}(?:[:/]|$))(?=[0-9-]*[A-Za-z])[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?):(?:~?[A-Za-z0-9._!$&'()*+,;=@-]+)(?:/[A-Za-z0-9._~!$&'()*+,;=@-]+)*/?)$",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept bracketed IPv6 hosts in marketplace URLs

When a Git or npm marketplace is hosted on an IPv6-only service, valid URLs such as ssh://git@[2001:db8::1]/team/repo.git and https://[2001:db8::1]:4873/ are rejected because this host grammar admits only DNS names and dotted-quad IPv4; the registry pattern on line 53 has the same limitation. Git accepts the SSH form as a remote URL, so these sources fail artifact validation before Codex can use them; parse the authority structurally or add bracketed IPv6 support to both patterns.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 82c0c41. The shared host grammar in gitUrl (both the scheme and scp-style branches) and npmSource.registry now has a third alternative: a bracketed RFC 3986 IP-literal covering every IPv6 form (full eight groups, :: compression at any position, and IPv4-embedded tails such as [::ffff:10.0.0.1]). Admitted fixtures: ssh://git@[2001:db8::1]/team/codex-plugins.git, https://[2001:db8::1]:4873/…, https://[::1]/…, git@[2001:db8::1]:team/codex-plugins.git, and registries https://[2001:db8::1]:4873/ / https://[::1]/. Rejected: unbracketed https://2001:db8::1/…, unterminated [2001:db8::1, non-hex groups, nine groups, seven uncompressed groups, and []. Pins and PROVENANCE notes updated.

"type": "string"
},
"source": { "const": "npm", "type": "string" },
"version": { "minLength": 1, "pattern": "^(?:(?:v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)? - v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?|(?:(?:[<>]=?|=|~>?|\\^) ?)?v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?(?: (?:(?:[<>]=?|=|~>?|\\^) ?)?v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?)*)(?: ?\\|\\| ?(?:v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)? - v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?|(?:(?:[<>]=?|=|~>?|\\^) ?)?v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?(?: (?:(?:[<>]=?|=|~>?|\\^) ?)?v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?)*))*|[A-Za-z0-9!'()*._~-]+)$", "type": "string" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept valid whitespace in npm semver ranges

Fresh evidence after the earlier selector fix: a valid npm range such as >=1.0.0 <2.0.0 is rejected because comparator intersections and hyphen ranges require exactly one ASCII space. npm 11.4.2's bundled npm-package-arg classifies this selector as a range and semver.validRange accepts it, so real-world marketplaces containing repeated whitespace or tabs now fail artifact validation before Codex/npm can consume them; use npm's whitespace grammar rather than literal single spaces.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 82c0c41. The version pattern now follows semver's Range normalisation (range.trim().split(/\s+/) plus the COMPARATORTRIM/HYPHENRANGE \s+ rules): any whitespace run between comparators, between an operator and its version, and around the hyphen in a hyphen range, with leading/trailing whitespace tolerated. Newly admitted fixtures: >=1.0.0 <2.0.0, >=1.0.0\t<2.0.0, >= 1.0.0, ~ 1.2, 1.2.3, 1.0.0 - 2.0.0, ^1||^2. 1.0.0 -2.0.0 is added as a rejected fixture since semver parses -2.0.0 as an invalid comparator there.

…n marketplace URL and version patterns

Git URLs, scp-style remotes, and npm registries now admit RFC 3986 IP-literal
hosts such as ssh://git@[2001:db8::1]/repo.git and https://[::1]:4873/, and
npm `version` follows semver's whitespace grammar (any whitespace run between
comparators or around a hyphen range, trimmed at the ends) instead of a
single literal space.

Addresses the fourth-round Codex review threads on #392.
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 82c0c413bb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

"type": "string"
},
"source": { "const": "npm", "type": "string" },
"version": { "minLength": 1, "pattern": "^(?:\\s*(?:v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?\\s+-\\s+v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?|(?:(?:[<>]=?|=|~>?|\\^)\\s*)?v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?(?:\\s+(?:(?:[<>]=?|=|~>?|\\^)\\s*)?v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?)*)(?:\\s*\\|\\|\\s*(?:v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?\\s+-\\s+v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?|(?:(?:[<>]=?|=|~>?|\\^)\\s*)?v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?(?:\\s+(?:(?:[<>]=?|=|~>?|\\^)\\s*)?v?(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:\\.(?:[xX*]|0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?)?)?)*))*\\s*|[A-Za-z0-9!'()*._~-]+)$", "type": "string" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject path-like npm version selectors

Fresh evidence after the earlier selector fix: when an npm source uses version: ".", "..", or ".foo", the final dist-tag alternative accepts it, but npm 11.4.2's bundled npm-package-arg classifies each as type: "directory" (isPosixFile treats any dot-prefixed spec as a file spec), not as a registry version, range, or tag. These accepted values therefore violate the documented prohibition on path selectors and can make Codex resolve a local directory or fail installation instead of fetching the requested package; exclude dot-prefixed path forms or validate the selector with npm's parser.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c395a7e. The dist-tag alternative now carries a (?!\.) guard so ., .., .foo, and .latest (all type: "directory" under npm-package-arg's isFileSpec) are rejected; those four are added as rejected fixtures and the PROVENANCE note records the rule. The other file-spec prefixes (/, \\, ~/, drive letters) were already excluded by the character class.

"pattern": "^(?:(?:[Hh][Tt][Tt][Pp][Ss]?|[Ss][Ss][Hh])://(?:[A-Za-z0-9._~!$&'()*+,;=-]+@)?(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|\\[(?:(?:[0-9A-Fa-f]{1,4}:){6}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|::(?:[0-9A-Fa-f]{1,4}:){5}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::)\\]|(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)*(?=[A-Za-z0-9-]{1,63}(?:[:/]|$))(?=[0-9-]*[A-Za-z])[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)(?::0*(?:0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?(?:/(?:[A-Za-z0-9._~!$&'()*+,;=:@-]|%[0-9A-Fa-f]{2})+)+/?|[A-Za-z0-9._-]+@(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|\\[(?:(?:[0-9A-Fa-f]{1,4}:){6}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|::(?:[0-9A-Fa-f]{1,4}:){5}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::)\\]|(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)*(?=[A-Za-z0-9-]{1,63}(?::|$))(?=[0-9-]*[A-Za-z])[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?):(?:~?[A-Za-z0-9._!$&'()*+,;=@-]+)(?:/[A-Za-z0-9._~!$&'()*+,;=@-]+)*/?)$",
"type": "string"
},
"gitRef": { "minLength": 1, "type": "string" },

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate Git refs before admitting marketplace sources

When a URL or git-subdir source supplies an invalid ref such as ref: "foo bar", this definition accepts it solely because it is nonempty, even though git check-ref-format --branch 'foo bar' exits 128 with fatal: 'foo bar' is not a valid branch name; control characters, .., @{, and .lock suffixes are admitted similarly. Such a marketplace passes artifact validation only to become unresolvable during Git installation, so apply Git's ref-name restrictions rather than accepting arbitrary text.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in c395a7e. gitRef now has a pattern implementing git check-ref-format: no control characters, space, or ~^:?*[\\; no .. or @{; components cannot be empty, start with ., or end with . or .lock; no leading - (so a ref cannot be parsed as a git option) and no lone @. Admitted fixtures: main, release/1.2, v1.2.3, refs/tags/v1.2.3, feature/foo.bar, HEAD, user/-dash, x.lockfile, a@b. 24 rejected refs (foo bar, foo..bar, foo@{1}, @, -main, main.lock, a.lock/b, refs/heads/, /main, a//b, main., .hidden, a/.b, each forbidden character, tab, DEL, newline) are asserted for both url and git-subdir sources.

… dot-prefixed npm dist-tags

`ref` selectors now follow git check-ref-format (no control characters,
whitespace, ~^:?*[\, "..", or "@{"; no empty, dot-leading, ".lock"- or
dot-trailing components; no leading "-" or lone "@"), and npm `version`
dist-tags may not start with "." because npm-package-arg classifies those as
directory specs rather than registry selectors.

Addresses the fifth-round Codex review threads on #392.
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c395a7e4ed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

},
"gitUrl": {
"minLength": 1,
"pattern": "^(?:(?:[Hh][Tt][Tt][Pp][Ss]?|[Ss][Ss][Hh])://(?:[A-Za-z0-9._~!$&'()*+,;=-]+@)?(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|\\[(?:(?:[0-9A-Fa-f]{1,4}:){6}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|::(?:[0-9A-Fa-f]{1,4}:){5}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::)\\]|(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)*(?=[A-Za-z0-9-]{1,63}(?:[:/]|$))(?=[0-9-]*[A-Za-z])[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?)(?::0*(?:0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?(?:/(?:[A-Za-z0-9._~!$&'()*+,;=:@-]|%[0-9A-Fa-f]{2})+)+/?|[A-Za-z0-9._-]+@(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|\\[(?:(?:[0-9A-Fa-f]{1,4}:){6}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|::(?:[0-9A-Fa-f]{1,4}:){5}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?:\\.(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3})|(?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::)\\]|(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)*(?=[A-Za-z0-9-]{1,63}(?::|$))(?=[0-9-]*[A-Za-z])[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?):(?:~?[A-Za-z0-9._!$&'()*+,;=@-]+)(?:/[A-Za-z0-9._~!$&'()*+,;=@-]+)*/?)$",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept standard Git URL userinfo

Fresh evidence after the earlier authority fix: when a private marketplace uses a standard credentialed URL such as https://user:token@git.example.test/team/plugin.git, this pattern rejects it because the optional userinfo character class omits : and percent escapes. Git 2.43 parses that form and proceeds to connect, while the schema already intends to support userinfo by accepting https://token@...; parse the URL structurally or expand the userinfo grammar so usable authenticated Git sources are not rejected before Codex can resolve them.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e629711. The gitUrl userinfo group is now RFC 3986 *( unreserved / pct-encoded / sub-delims / ":" ), so https://user:token@git.example.test/…, https://user%40corp:p%3Ass@…, and credentialed IPv4/IPv6 authorities are admitted (fixtures added). Rejected fixtures confirm credentials cannot mask a missing or malformed authority (user:token@/…, user:token@%zz/…, :65536, 999.999.999.999), and that raw spaces, bad escapes (us%zzer@), and a doubled @ still fail. npmSource.registry deliberately stays credential-free as documented in PROVENANCE, since npm reads registry auth from .npmrc, not the URL.

… in marketplace Git URLs

Credentialed Git sources such as https://user:token@git.example.test/repo.git
are valid to Git and were already half-supported (bare token@ passed); the
userinfo grammar now matches RFC 3986 while still refusing a masked bad
authority, raw spaces, malformed escapes, or a repeated "@".

Addresses the sixth-round Codex review thread on #392.
@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: e6297110d8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ScriptedAlchemy
ScriptedAlchemy merged commit 325e7f4 into main Sep 3, 2026
16 of 17 checks passed
@ScriptedAlchemy
ScriptedAlchemy deleted the feat/188-s3-codex-marketplace-policy branch September 3, 2026 09:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant